import re



# 将版本号分解成epoch, upstream_version, debian_revision
# 同时处理一些特殊版本情况
def handle_version(ver_str):
    epoch = "0"
    upstream_ver = ver_str
    debian_revision = ""
    split_list1 = ver_str.split(':')  # 分解出epoch
    if len(split_list1) == 2:
        epoch = split_list1[0]
        upstream_ver = split_list1[1]
    # '+really' 规则，后面的才算数
    check_really = upstream_ver.split('+really')
    if len(check_really) > 1 :   # 有+really
        upstream_ver = check_really[1]
    # Non-maintainer uploads--nmu: +nmu +b
    # debian_revision中的+deb, ~bpo
    # （这些还没处理）
    split_list2 = upstream_ver.split('-')  # 分解出debian_revision
    if len(split_list2) == 2:
        upstream_ver = split_list2[0]
        debian_revision = split_list2[1]
    return epoch, upstream_ver, debian_revision


# 把字符串每个字符内容逐个转换成数字，形成list
# 是为了可以给'~'和''赋更靠前的值，从而符合Ubuntu版本规则
def str2list(old_str, new_len):
    new_list = []
    # ~符号最靠前
    for i in range(len(old_str)):
        if old_str[i] == '~':
            new_list.append(0)
        else:
            new_list.append(ord(old_str[i]))
    # 空的排序在字母前
    if len(old_str) < new_len:
        new_list += [2]*(new_len-len(old_str))
    return new_list


# 比较无数字的版本字符串
def compare_non_digit_str(str1, str2):
    # 还没有处理‘+’
    max_len = max(len(str1), len(str2))
    list1 = str2list(str1, max_len)
    list2 = str2list(str2, max_len)

    for i in range(max_len):
        if list1[i] < list2[i]:
            return -1
        elif list1[i] > list2[i]:
            return 1
    return 0

# asd = compare_non_digit_str('~~a', '~')
# print()


# 根据可满足Ubuntu版本限制的算法，比较每个.分割的str（例如ubuntu1）
def compare_ver_str_split(ver_str1, ver_str2):
    # 版本号比较
    pattern = r'(\D*)(\d*)(.*)'
    this_ver_str1 = ver_str1
    this_ver_str2 = ver_str2
    # 具体方法：先比较开头的非数字，然后数字，重复直到有结果或者耗尽
    while True:
        ver1_groups = re.match(pattern, this_ver_str1).groups()
        ver2_groups = re.match(pattern, this_ver_str2).groups()
        ver1_non_digit = ver1_groups[0]
        ver2_non_digit = ver2_groups[0]
        res = compare_non_digit_str(ver1_non_digit, ver2_non_digit)
        if res != 0:
            return res
        try:
            ver1_digit = int(ver1_groups[1])  # 这里转换成int没问题吗？-> 01和1
        except ValueError:  # 空字符串
            ver1_digit = 0
        try:
            ver2_digit = int(ver2_groups[1])
        except ValueError:  # 空字符串
            ver2_digit = 0
        if ver1_digit < ver2_digit:
            return -1
        if ver1_digit > ver2_digit:
            return 1
        this_ver_str1 = ver1_groups[2]
        this_ver_str2 = ver2_groups[2]
        if this_ver_str1 == '' and this_ver_str2 == '':  # 始终相等
            return 0

# 比较带.的字符串（例如1.5.2a）
def compare_ver_str(ver_str1, ver_str2):
    ver_list1 = ver_str1.split('.')
    ver_list2 = ver_str2.split('.')
    # 对齐列表，没有的默认为0
    if len(ver_list1) > len(ver_list2):
        ver_list2.extend('0' * (len(ver_list1) - len(ver_list2)))
    else:
        ver_list1.extend('0' * (len(ver_list2) - len(ver_list1)))
    list_len = len(ver_list1)
    for i in range (list_len):
        res = compare_ver_str_split(ver_list1[i], ver_list2[i])
        if res != 0:
            return res
    return 0


# asd = compare_ver_str('1.0~beta1~svn1245', '1.0~beta1')


# 给定两个字符串格式版本号，比较两个版本
def compare_version(version_str1, version_str2):
    epoch1, upstream_ver1, debian_revision1 = handle_version(version_str1)
    epoch2, upstream_ver2, debian_revision2 = handle_version(version_str2)
    # 先比较epoch
    try:  # epoch不是纯数字
        if int(epoch1) < int(epoch2):
            return -1
        if int(epoch1) > int(epoch2):
            return 1
    except Exception:
        print("Error: 'epoch' is not all digit")
        return 0
    # 再比较upstream
    res = compare_ver_str(upstream_ver1, upstream_ver2)
    if res != 0:
        return res
    # 再比较debian_revision
    res = compare_ver_str(debian_revision1, debian_revision2)
    return res


# 给定版本字符串和限制条件，给出是否满足
def verSatisfy(ver, constr_op, constr_ver):
    compare_res = compare_version(ver, constr_ver)
    if (compare_res == -1 and (constr_op == '<<' or constr_op == '<=')) \
        or (compare_res == 1 and (constr_op == '>>' or constr_op == '>=')) \
        or (compare_res == 0 and (constr_op == '<=' or constr_op == '>='or constr_op == '=')):
        return True


def verSatisfyAll(ver, constr_str_list):
    for constr_opVer in constr_str_list:
        if verSatisfy(ver, constr_opVer[0], constr_opVer[1]) is False:
            return False
    return True


# asd = compare_version("1.4+deb11u1", "1.4+deb10u2")
# print()